import math
from collections import defaultdict
from typing import *

from pyautogui import *

from UAC import is_admin, __set_run_as_admin
from algorithm import *

PAUSE = 0
conf = 0.9  # 识别图像的精准度
eps = 10  # 两个点曼哈顿距离在 eps 以下认为是同一个点


def draw(points: List[Point], order: list):
    moveTo(*points[order[0]])
    mouseDown()
    for i in order:
        x, y = points[i]
        moveTo(x, y)
    mouseUp()


def convertRGBToGray(r, g, b):
    return r * 0.299 + g * 0.587 + b * 0.114


def dis(a, b) -> float:
    x0, y0 = a
    x1, y1 = b
    return math.fabs(x0 - x1) + math.fabs(y0 - y1)


def locatePoints() -> List[Point]:
    ps = locateAllOnScreen('./point.png', confidence=conf)
    xy = sorted([center(p) for p in ps], key=lambda x: (x.y, x.x))
    target = []
    for i in xy:
        has = False
        for j in target:
            if dis(i, j) <= eps:
                has = True
                break
        if not has:
            target.append(i)
    return target


def locateOpen():
    op = locateOnScreen('./open.png', confidence=conf)
    return center(op)


def locateRedo():
    return center(locateOnScreen('./redo.png', confidence=conf))


def isRed(p):
    r, g, b = p
    return convertRGBToGray(r, g, b) <= 200


def isConnect(s_id, e_id):
    global points
    sx, sy = points[s_id]
    ex, ey = points[e_id]
    mx = (sx + ex) >> 1
    my = (sy + ey) >> 1
    ss = screenshot()
    return isRed(ss.getpixel((sx, sy))) and isRed(ss.getpixel((ex, ey))) and isRed(ss.getpixel((mx, my)))


def tryConnect(s_id, e_id):
    global points
    sx, sy = points[s_id]
    ex, ey = points[e_id]
    moveTo(sx, sy)
    mouseDown()
    moveTo(ex, ey)
    mouseUp()
    return isConnect(s_id, e_id)


def redo():
    rx, ry = redoButton
    moveTo(rx, ry)
    click(rx, ry)


def locateEdges():
    global points
    edges = defaultdict(set)
    for i in range(len(points)):
        for j in range(i + 1, len(points)):
            if tryConnect(i, j):
                edges[i].add(j)
                edges[j].add(i)
                redo()
                print(f'find edge: {i, j}')
        redo()
    return edges


if __name__ == '__main__':
    if not is_admin():
        print("请以管理员身份运行!!!")
        __set_run_as_admin(__file__)
    if is_admin():
        points = locatePoints()
        openButton = locateOpen()
        redoButton = locateRedo()
        print(*points, sep="\n")
        print('-----------------------------')
        print(f'{len(points)} points')
        print(f'openButton on {openButton}')
        print(f'redoButton on {redoButton}')
        input('If number of points is right, please press enter to start...')
        startTime = time.time()
        redo()
        edges = locateEdges()
        print('calculating answer...')
        ans = Euler(len(points), edges).getPath()
        print('ok, find ans:')
        print(ans)
        draw(points, ans)
        endTime = time.time()
        print('cost {:.2f}min'.format((endTime - startTime) / 60))
        input('finish...')
